package com.hashimoto.core.remote.server;

import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hashimoto.core.handler.business.ServerHandler;
import com.hashimoto.core.handler.decodec.CodecAdapter;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.DefaultThreadFactory;

public class NettyServer extends Server {
	
	private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
	
	private ServerBootstrap bootstrap;

	private io.netty.channel.Channel channel;

	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;

	private ServerProcessingHandler processingHandler;
	
	@Override
	public void excepton(Throwable t) {

	}
	
	@Override
	public void start() {
		
		bootstrap = new ServerBootstrap();
		bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
	    workerGroup = new NioEventLoopGroup(threadNum,new DefaultThreadFactory("NettyServerWorker", true));
	    bootstrap.group(bossGroup, workerGroup)
        .channel(NioServerSocketChannel.class)
        .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
        .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
        .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
        .childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                CodecAdapter adapter = new CodecAdapter();
                ch.pipeline()
                        .addLast("decoder", adapter.getDecode())
                        .addLast("encoder", adapter.getEncode())
                        .addLast("handler", new ServerHandler(handler()));
            }
        });
		try {
			//boolean isOpen = false;
			ChannelFuture f =bootstrap.bind(this.getPort()).addListener(future ->{
				if (future.isSuccess()) {
					
		            log.info("open the server is success");
		        } else {
		        	log.error("open the server is false");
		        }
			}).sync();
			if(f.isSuccess()) {
				this.channel = f.channel();
			}
			f.channel().closeFuture().addListener(future ->{
				 stop();
			});
			
		} catch (InterruptedException e) {
			log.error("open the port {} server is error",getPort());
		}
	}
	private ServerProcessingHandler handler() {
		processingHandler = new NettyServerProcessHandler();
		processingHandler.setLoginAuthHandler(getAuthHandler());
		processingHandler.setReceivedListener(getListener());
		return processingHandler;
	}

	@Override
	public void stop() {
		if(processingHandler != null) {
			processingHandler.clearUp();
		}
		if(bossGroup != null) {
			bossGroup.shutdownGracefully();  
		}
		
		if(workerGroup != null) {
			workerGroup.shutdownGracefully();
		}
	}

	@Override
	public boolean isActive() {
		return channel != null ? channel.isActive() : false;
	}
	
	@Override
	public SocketAddress localAddress() {
		return  channel != null ? channel.localAddress() : null;
	}
	
	public static void main(String[] args) {
//		NettyServer server = new NettyServer();
//		server.setPort(9999);
//		server.setThreadCount(100);
//		server.setAuthHandler(new DefaultLoginAuthHandler());
//		server.setListener(new DefaultReceivedListener());
//		server.start();
//		
//		
//		try {
//			Thread.sleep(1000000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
	}


}
